package org.dromara.common.mybatis.handler

import cn.hutool.http.HttpStatus
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler
import io.github.oshai.kotlinlogging.KotlinLogging
import org.apache.ibatis.reflection.MetaObject
import org.dromara.common.core.domain.model.LoginUser
import org.dromara.common.core.exception.ServiceException
import org.dromara.common.core.utils.ObjectUtils
import org.dromara.common.mybatis.core.domain.BaseEntity
import org.dromara.common.satoken.utils.LoginHelper
import org.dromara.common.satoken.utils.LoginHelper.getUserId
import java.util.*

/**
 * MP注入处理器
 *
 * @author Lion Li
 * @updater LikeYouDo
 * @date 2025/1/27 0:28
 */
open class InjectionMetaObjectHandler : MetaObjectHandler {
    companion object {
        private val log = KotlinLogging.logger { }

        /**
         * 如果用户不存在默认注入-1代表无用户
         */
        private const val DEFAULT_USER_ID: Long = -1L

    }

    /**
     * 插入填充方法，用于在插入数据时自动填充实体对象中的创建时间、更新时间、创建人、更新人等信息
     *
     * @param metaObject 元对象，用于获取原始对象并进行填充
     */
    override fun insertFill(metaObject: MetaObject) {
        try {
            if (metaObject.originalObject is BaseEntity) {
                val baseEntity = metaObject.originalObject as BaseEntity
                // 获取当前时间作为创建时间和更新时间，如果创建时间不为空，则使用创建时间，否则使用当前时间
                val current = ObjectUtils.notNull(baseEntity.createTime, Date())
                baseEntity.createTime = current
                baseEntity.updateTime = current

                // 如果创建人为空，则填充当前登录用户的信息
                if (baseEntity.createBy === null) {
                    val loginUser = getLoginUser()
                    if (loginUser !== null) {
                        val userId = loginUser.userId
                        // 填充创建人、更新人和创建部门信息
                        baseEntity.createBy = userId
                        baseEntity.updateBy = userId
                        baseEntity.createDept = ObjectUtils.notNull(baseEntity.createDept, loginUser.deptId)
                    } else {
                        // 填充创建人、更新人和创建部门信息
                        baseEntity.createBy = DEFAULT_USER_ID
                        baseEntity.updateBy = DEFAULT_USER_ID
                        baseEntity.createDept = ObjectUtils.notNull(baseEntity.createDept, DEFAULT_USER_ID)
                    }
                }
            } else {
                val date = Date()
                this.strictInsertFill(
                    metaObject, "createTime",
                    Date::class.java, date
                )
                this.strictInsertFill(
                    metaObject, "updateTime",
                    Date::class.java, date
                )
            }
        } catch (e: Exception) {
            throw ServiceException("自动注入异常 => " + e.message, HttpStatus.HTTP_UNAUTHORIZED)
        }
    }

    /**
     * 更新填充方法，用于在更新数据时自动填充实体对象中的更新时间和更新人信息
     *
     * @param metaObject 元对象，用于获取原始对象并进行填充
     */
    override fun updateFill(metaObject: MetaObject) {
        try {
            if (metaObject.originalObject is BaseEntity) {
                val baseEntity = metaObject.originalObject as BaseEntity
                // 获取当前时间作为更新时间，无论原始对象中的更新时间是否为空都填充
                baseEntity.updateTime = Date()

                // 获取当前登录用户的ID，并填充更新人信息
                val userId = getUserId()
                if (userId !== null) {
                    baseEntity.updateBy = userId
                } else {
                    baseEntity.updateBy = DEFAULT_USER_ID
                }
            } else {
                this.strictUpdateFill(
                    metaObject, "updateTime",
                    Date::class.java, Date()
                )
            }
        } catch (e: Exception) {
            throw ServiceException("自动注入异常 => " + e.message, HttpStatus.HTTP_UNAUTHORIZED)
        }
    }

    /**
     * 获取当前登录用户信息
     *
     * @return 当前登录用户的信息，如果用户未登录则返回 null
     */
    private fun getLoginUser(): LoginUser? {
        val loginUser: LoginUser?
        try {
            loginUser = LoginHelper.getLoginUser()
        } catch (e: Exception) {
            return null
        }
        return loginUser
    }
}
